using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Utilities;



namespace Services.Menu
{
    public enum SelectorType
    {
        A_B_C,
        A_B,
        A,
        B,
        B_C,
        C
    }
    enum DraggingType
    {
        A,
        B,
        C,
        None
    }
    public abstract class ASelectorScreen : DrawableGameComponent
    {
        SpriteBatch spritebatch;
        InputManager input_manager;
        protected MyButton confirm, cancel, title;
        protected MyButton upper_box;
        protected MyButton lower_box;
        //Matrix screen_transform;
        //AStateManager StateManager;

        protected Action<DateTime> closeSelector;
        Action abortSelection;
        //TimeSpan defaultTimeSpan;
        SelectorType type;
        String titleString;
        DraggingType current_dragging = DraggingType.None;
        protected ArrayList<MyButton> listA, listB, listC;
        protected Texture2D box, white;
        protected Rectangle areaA, areaB, areaC;
        protected Rectangle dragAreaA, dragAreaB, dragAreaC;
        protected int selectedAValue;
        protected int selectedBValue;
        protected int selectedCValue;
        protected DisplayOrientation prev_orientation;
        protected SpriteFont font, small;
        protected Texture2D ok, no, circle;
        #region Constructors
        public ASelectorScreen(Game game, Action<DateTime> closeSelector, Action abortSelection,
            int selectedA, int selectedB, int selectedC, SelectorType type, String titleString)
            : base(game)
        {
            this.closeSelector = closeSelector;
            //this.defaultTimeSpan = defaultTimeSpan;
            this.type = type;
            this.titleString = titleString;
            this.abortSelection = abortSelection;
            this.selectedAValue = selectedA;
            this.selectedBValue = selectedB;
            this.selectedCValue = selectedC;
            
        }

        #endregion

        public override void Initialize()
        {
            spritebatch = (SpriteBatch)Game.Services.GetService(typeof(SpriteBatch));
            //StateManager = (AStateManager)Game.Services.GetService(typeof(AStateManager));
            input_manager = new InputManager(Game);
            Game.Components.Add(input_manager);
            input_manager.OnTap += on_tap;
            input_manager.OnDrag += on_drag;
            input_manager.OnHorizontalDrag += on_drag;
            input_manager.OnVerticalDrag += on_drag;
            input_manager.OnDragCompleted += on_drag_completed;
            //screen_transform = Game.ScreenTransformMatrix(graphics);
            font = Game.Content.Load<SpriteFont>("DateTimeSelector\\font");
            small = Game.Content.Load<SpriteFont>("DateTimeSelector\\small");
            ok = Game.Content.Load<Texture2D>("DateTimeSelector\\ok");
            no = Game.Content.Load<Texture2D>("DateTimeSelector\\cancel");
            circle = Game.Content.Load<Texture2D>("DateTimeSelector\\circle");
            white = Game.Content.Load<Texture2D>("DateTimeSelector\\whitepixel");
            box = Game.Content.Load<Texture2D>("DateTimeSelector\\box");
            title = new MyButton(new Rectangle(0, 0, 200, 80), titleString, Color.White, font, TextPos.Left);
            title.textScale = 0.5f;

            listA = new ArrayList<MyButton>();
            listB = new ArrayList<MyButton>();
            listC = new ArrayList<MyButton>();
            base.Initialize();
            ChangeOrientation();

            //selectedAValue = SearchSelected(listA, areaA, true, defaultTimeSpan.Hours);
            //selectedBValue = SearchSelected(listB, areaB, true, defaultTimeSpan.Minutes);
            //selectedCValue = SearchSelected(listC, areaC, true, defaultTimeSpan.Seconds);
            selectedAValue = SearchSelected(listA, areaA, true, selectedAValue);
            selectedBValue = SearchSelected(listB, areaB, true, selectedBValue);
            selectedCValue = SearchSelected(listC, areaC, true, selectedCValue);
        }

        protected override void LoadContent()
        {


            base.LoadContent();
        }
        protected void ChangeOrientation()
        {
            prev_orientation = GraphicsDevice.PresentationParameters.DisplayOrientation;
            if (prev_orientation == DisplayOrientation.LandscapeLeft || prev_orientation == DisplayOrientation.LandscapeRight)
            {
                if (prev_orientation == DisplayOrientation.LandscapeRight)
                {
                    confirm = new MyButton(new Rectangle(20, 160, 60, 60), ok, Color.White, circle, Color.White);
                    cancel = new MyButton(new Rectangle(20, 260, 60, 60), no, Color.White, circle, Color.White);
                }
                else
                {
                    confirm = new MyButton(new Rectangle(720, 160, 60, 60), ok, Color.White, circle, Color.White);
                    cancel = new MyButton(new Rectangle(720, 260, 60, 60), no, Color.White, circle, Color.White);
                }


                upper_box = new MyButton(new Rectangle(0, 0, 800, 80), white, Color.Black);

                lower_box = new MyButton(new Rectangle(0, 480, 0, 0), white, Color.Black);
                SetLandScapeOrientation();
            }
            else
            {
                confirm = new MyButton(new Rectangle(160, 720, 60, 60), ok, Color.White, circle, Color.White);
                cancel = new MyButton(new Rectangle(260, 720, 60, 60), no, Color.White, circle, Color.White);

                upper_box = new MyButton(new Rectangle(0, 0, 480, 80), white, Color.Black);
                lower_box = new MyButton(new Rectangle(0, 700, 480, 100), white, Color.Black);
                SetPortraitOrientation();
            }
        }
        float prev_velocity;
        public override void Update(GameTime gameTime)
        {
            float dt = (float)gameTime.ElapsedGameTime.TotalSeconds;
            if (prev_orientation != GraphicsDevice.PresentationParameters.DisplayOrientation)
            {
                ChangeOrientation();
                if (velocity == 0)
                {
                    selectedAValue = SearchSelected(listA, areaA, true, selectedAValue);
                    selectedBValue = SearchSelected(listB, areaB, true, selectedBValue);
                    selectedCValue = SearchSelected(listC, areaC, true, selectedCValue);
                }
            }
            
            if (velocity != 0 && current_dragging!= DraggingType.None)
            {
                prev_velocity = velocity;
                if (velocity < 0)
                {
                    velocity += dt * 4;
                    if (velocity > 0)
                        velocity = 0;
                }
                else
                {
                    velocity -= dt * 4;
                    if (velocity < 0)
                        velocity = 0;
                }
                //if (Math.Abs(velocity) < 0.5f)
                //    velocity = 0;
                var delta_y = (int)velocity;
                if (current_dragging == DraggingType.A)
                {
                    if (listA.Count > 0 && listA[listA.Count - 1].rectangle.Y < areaA.Y)
                    {
                        velocity = 0;
                        delta_y = areaA.Y - listA[listA.Count - 1].rectangle.Y;
                    }
                    if (listA.Count > 0 && listA[0].rectangle.Y > areaA.Y)
                    {
                        velocity = 0;
                        delta_y = areaA.Y - listA[0].rectangle.Y;
                    }
                    for (int i = 0; i < listA.Count; i++)
                    {
                        listA[i].rectangle.Y += delta_y;
                        listA[i].UpdateTextPos();
                    }
                }
                else if (current_dragging == DraggingType.B)
                {
                    if (listB.Count > 0 && listB[listB.Count - 1].rectangle.Y < areaB.Y)
                    {
                        velocity = 0;
                        delta_y = areaB.Y - listB[listB.Count - 1].rectangle.Y;
                    }
                    if (listB.Count > 0 && listB[0].rectangle.Y > areaB.Y)
                    {
                        velocity = 0;
                        delta_y = areaB.Y - listB[0].rectangle.Y;
                    }
                    for (int i = 0; i < listB.Count; i++)
                    {
                        listB[i].rectangle.Y += delta_y;
                        listB[i].UpdateTextPos();
                    }
                }
                else if (current_dragging == DraggingType.C)
                {
                    MyButton last = listC[listC.Count - 1];
                    for (int i = listC.Count - 1; i >= 0; i--)
                        if (listC[i].enabled)
                        {
                            last = listC[i];
                            break;
                        }

                    if (listC.Count > 0 && last.rectangle.Y < areaC.Y)
                    {
                        velocity = 0;
                        delta_y = areaC.Y - last.rectangle.Y;
                    }
                    if (listC.Count > 0 && listC[0].rectangle.Y > areaC.Y)
                    {
                        velocity = 0;
                        delta_y = areaC.Y - listC[0].rectangle.Y;
                    }
                    for (int i = 0; i < listC.Count; i++)
                    {
                        listC[i].rectangle.Y += delta_y;
                        listC[i].UpdateTextPos();
                    }
                }

            }
            else if(prev_velocity !=0)
            {
                SetSelectedValues();
                current_dragging = DraggingType.None;
                velocity = 0;
                prev_velocity = velocity;
            }
            else
                current_dragging = DraggingType.None;
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            {
                Game.Components.Remove(input_manager);
                Game.Components.Remove(this);
                abortSelection();   
            } 
            base.Update(gameTime);
        }
        protected int SearchSelected(ArrayList<MyButton> list, Rectangle area, bool setToValue, int selectedValue)
        {
            int selected = 0;
            float min = float.MaxValue;
            int deltay;
            Vector2 v1 = new Vector2(area.Center.X, area.Center.Y);
            if (!setToValue)
            {
                for (int i = 0; i < list.Count; i++)
                {
                    list[i].texture = box;
                    list[i].textColor = Color.White;
                    list[i].textColor2 = Color.White;
                    var d = Vector2.Distance(v1, new Vector2(list[i].rectangle.Center.X, list[i].rectangle.Center.Y));
                    if (d < min)
                    {
                        min = d;
                        selected = i;
                    }
                }
            }
            else
            {
                selected = selectedValue;
            }
            if (selected < 0)
                selected = 0;
            else if (selected >= list.Count)
                selected = list.Count - 1;
            if (selected < 0)
                return 0;
            list[selected].texture = white;
            list[selected].textColor = Color.Black;
            list[selected].textColor2 = Color.Black;
            deltay = area.Y - list[selected].rectangle.Y;
            for (int i = 0; i < list.Count; i++)
            {
                list[i].rectangle.Y += deltay;
                list[i].UpdateTextPos();
            }
            return selected;
        }
        public override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);

            //spritebatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, screen_transform);
            spritebatch.Begin();

            for (int i = 0; i < listA.Count; i++)
                listA[i].Draw(spritebatch);
            for (int i = 0; i < listB.Count; i++)
                listB[i].Draw(spritebatch);
            for (int i = 0; i < listC.Count; i++)
                listC[i].Draw(spritebatch);

            upper_box.Draw(spritebatch);
            lower_box.Draw(spritebatch);
            title.Draw(spritebatch);
            confirm.Draw(spritebatch);
            cancel.Draw(spritebatch);
            spritebatch.End();

            base.Draw(gameTime);
        }
        void on_tap(Vector2 tap_pos)
        {
            if (confirm.tapped_on(tap_pos))
            {
                if (velocity != 0)
                    return;
                Game.Components.Remove(input_manager);
                Game.Components.Remove(this);
                ExitSelector();
            }
            else if (cancel.tapped_on(tap_pos))
            {
                Game.Components.Remove(input_manager);
                Game.Components.Remove(this);
                abortSelection();
            }
            else
            {
                velocity = 0;
                //switch (current_dragging)
                //{
                //    case DraggingType.A:
                //        selectedAValue = SearchSelected(listA, areaA, false, 0);
                //        break;
                //    case DraggingType.B:
                //        selectedBValue = SearchSelected(listB, areaB, false, 0);
                //        break;
                //    case DraggingType.C:
                //        selectedCValue = SearchSelected(listC, areaC, false, 0);
                //        break;
                //}
                SetSelectedValues();
                
            }
        }

        protected virtual void SetSelectedValues()
        {
            switch (current_dragging)
            {
                case DraggingType.A:
                    selectedAValue = SearchSelected(listA, areaA, false, 0);
                    break;
                case DraggingType.B:
                    selectedBValue = SearchSelected(listB, areaB, false, 0);
                    break;
                case DraggingType.C:
                    selectedCValue = SearchSelected(listC, areaC, false, 0);

                    break;
            }
        }

        Vector2 prev_drag_pos;
        float velocity = 0;

        void on_drag(Vector2 drag_pos)
        {
            if (prev_drag_pos != Vector2.Zero)
            {
                if (RectContainsVect(dragAreaA, drag_pos))
                {
                    int offset = (int)(drag_pos.Y - prev_drag_pos.Y);
                    for (int i = 0; i < listA.Count; i++)
                        listA[i].rectangle.Y += offset;
                    velocity = offset;
                    current_dragging = DraggingType.A;
                }
                else if (RectContainsVect(dragAreaB, drag_pos))
                {
                    int offset = (int)(drag_pos.Y - prev_drag_pos.Y);
                    for (int i = 0; i < listB.Count; i++)
                        listB[i].rectangle.Y += offset;
                    velocity = offset;
                    current_dragging = DraggingType.B;
                }
                else
                    if (RectContainsVect(dragAreaC, drag_pos))
                    {
                        int offset = (int)(drag_pos.Y - prev_drag_pos.Y);
                        for (int i = 0; i < listC.Count; i++)
                            listC[i].rectangle.Y += offset;
                        velocity = offset;
                        current_dragging = DraggingType.C;
                    }
            }
            else
                SetSelectedValues();
            
            prev_drag_pos = drag_pos;
        }

        void on_drag_completed()
        {
            prev_drag_pos = Vector2.Zero;
            if (velocity == 0)
                velocity = 0.01f;
        }

        /*PREV_DRAG
        void on_drag(Vector2 drag_pos)
        {
            if (drag_start_point != Vector2.Zero)
            {
                var distance = Vector2.Distance(drag_start_point, drag_pos) / 12;

                //if (distance >= 20)
                //{
                if (velocity == 0)
                    distance *= 2;
                if (drag_pos.Y > drag_start_point.Y)
                {
                    if (velocity < 0)
                        velocity = 0;
                    velocity += distance;
                    velocity = Math.Min(velocity, 40);
                }
                else
                {
                    if (velocity > 0)
                        velocity = 0;
                    velocity -= distance;
                    velocity = Math.Max(velocity, -40);
                }
                drag_start_point = drag_pos;
            }
            else
            {
                drag_start_point = drag_pos;
                //for (int i = 0; i < hours.Count; i++)
                //    if (RectContainsVect(hours[i].rectangle, drag_pos))
                if (current_dragging != DraggingType.None)
                {
                    //switch (current_dragging)
                    //{
                    //    case DraggingType.A:
                    //        selectedAValue = SearchSelected(listA, areaA, false, -1);
                    //        break;
                    //    case DraggingType.B:
                    //        selectedBValue = SearchSelected(listB, areaA, false, -1);
                    //        break;
                    //    case DraggingType.C:
                    //        selectedCValue = SearchSelected(listC, areaA, false, -1);
                    //        break;
                    //}
                    SetSelectedValues();
                }
                if (RectContainsVect(dragAreaA, drag_pos))
                {
                    current_dragging = DraggingType.A;
                    return;
                }
                //for (int i = 0; i < seconds.Count; i++)
                //    if (RectContainsVect(seconds[i].rectangle, drag_pos))
                if (RectContainsVect(dragAreaB, drag_pos))
                {
                    current_dragging = DraggingType.B;
                    return;
                }
                //for (int i = 0; i < minutes.Count; i++)
                //    if (RectContainsVect(minutes[i].rectangle, drag_pos))
                if (RectContainsVect(dragAreaC, drag_pos))
                {
                    current_dragging = DraggingType.C;
                    return;
                }
            }
        }
        */
        /*PREV_DRAG_COMP
        void on_drag_completed()
        {
            drag_start_point = Vector2.Zero;

        }*/

        public bool RectContainsVect(Rectangle rect, Vector2 v)
        {
            return rect.X < v.X && rect.Y < v.Y && rect.X + rect.Width > v.X && rect.Y + rect.Height > v.Y;
        }

        public abstract void SetPortraitOrientation();

        public abstract void SetLandScapeOrientation();
        public abstract void ExitSelector();

        protected void UpdateSelectedValue()
        {
            //switch (current_dragging)
            //{
            //    case DraggingType.A:
            //        selectedBValue = SearchSelected(listB, areaB, true, selectedBValue);
            //        selectedCValue = SearchSelected(listC, areaC, true, selectedCValue);
            //        break;
            //    case DraggingType.B:
            //        selectedAValue = SearchSelected(listA, areaA, true, selectedAValue);
            //        selectedCValue = SearchSelected(listC, areaC, true, selectedCValue);
            //        break;
            //    case DraggingType.C:
            //        selectedAValue = SearchSelected(listA, areaA, true, selectedAValue);
            //        selectedBValue = SearchSelected(listB, areaB, true, selectedBValue);
            //        break;
            //}
            selectedAValue = SearchSelected(listA, areaA, true, selectedAValue);
            selectedBValue = SearchSelected(listB, areaB, true, selectedBValue);
            selectedCValue = SearchSelected(listC, areaC, true, selectedCValue);
        }
    }
}
